#include <catch2/catch.hpp>

#include "solution.hpp"

using namespace solution_024;

namespace
{

template<int remains, typename arg, typename... args>
struct append
{
    static ListNode* impl(arg val, args... vals) {
        ListNode* l = new ListNode(val);
        l->next = append<sizeof...(args)-1, args...>::impl(vals...);
        return l;
    }
};

template<typename arg>
struct append<0, arg> {
    static ListNode* impl(arg val) {
        return new ListNode(val);
    }
};

template<typename... args>
ListNode* make_list(args... vals)
{
    return append<sizeof...(args)-1, args...>::impl(vals...);
}

void destroy_list(ListNode* head)
{
    while (head) {
        auto node = head;
        head = head->next;
        delete node;
    }
}

std::vector<int> convert_and_destroy(ListNode* list)
{
    std::vector<int> ilist;
    while (list) {
        ilist.push_back(list->val);
        list = list->next;
    }
    destroy_list(list);
    return ilist;
}

}

TEST_CASE("24. Swap Nodes in Pairs", "[024]") {

CHECK(convert_and_destroy(Solution().swapPairs(nullptr))                     == std::vector<int>{});
CHECK(convert_and_destroy(Solution().swapPairs(make_list(1)))                == std::vector{1});
CHECK(convert_and_destroy(Solution().swapPairs(make_list(1, 2)))             == std::vector{2, 1});
CHECK(convert_and_destroy(Solution().swapPairs(make_list(1, 2)))             == std::vector{2, 1});
CHECK(convert_and_destroy(Solution().swapPairs(make_list(1, 2, 3)))          == std::vector{2, 1, 3});
CHECK(convert_and_destroy(Solution().swapPairs(make_list(1, 2, 3, 4)))       == std::vector{2, 1, 4, 3});
CHECK(convert_and_destroy(Solution().swapPairs(make_list(1, 2, 3, 4, 5)))    == std::vector{2, 1, 4, 3, 5});
CHECK(convert_and_destroy(Solution().swapPairs(make_list(1, 2, 3, 4, 5, 6))) == std::vector{2, 1, 4, 3, 6, 5});

}
